---
title: "Collections - Arrays, Dictionaries, and Sets"
description: "Learn Swift collections: arrays, dictionaries, and sets with JavaScript comparisons"
---

# Collections: Arrays, Dictionaries, and Sets

In this module, we'll explore Swift's collection types and compare them with JavaScript's array and object structures. Swift provides three main collection types: Arrays, Dictionaries, and Sets, each with strong typing and powerful functional programming capabilities.

## Table of Contents

- [Arrays](#arrays)
- [Dictionaries](#dictionaries)
- [Sets](#sets)
- [Collection Operations](#collection-operations)
- [Functional Programming with Collections](#functional-programming-with-collections)
- [Performance Considerations](#performance-considerations)
- [Exercises](#exercises)
- [Key Takeaways](#key-takeaways)

## Arrays

Arrays in Swift are ordered collections of elements with the same type, similar to JavaScript arrays but with strong typing.

### Array Declaration and Initialization

<UniversalEditor title="Array Declaration Comparison" compare={true}>
```javascript !! js
// JavaScript: Dynamic typing, can mix types
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, { name: "John" }];

// Creating empty arrays
let emptyArray = [];
let arrayWithSize = new Array(5); // Creates array with 5 undefined elements

// Array with repeated values
let repeated = Array(3).fill("hello");
```

```swift !! swift
// Swift: Strong typing, all elements must be same type
var numbers: [Int] = [1, 2, 3, 4, 5]
var names: [String] = ["Alice", "Bob", "Charlie"]

// Type inference
var scores = [85, 92, 78, 96] // Swift infers [Int]

// Creating empty arrays
var emptyArray: [Int] = []
var emptyArray2 = [Int]()

// Array with repeated values
var repeated = Array(repeating: "hello", count: 3)
```
</UniversalEditor>

### Array Access and Modification

<UniversalEditor title="Array Access and Modification" compare={true}>
```javascript !! js
// JavaScript array access
let fruits = ["apple", "banana", "orange"];
console.log(fruits[0]); // "apple"
console.log(fruits.length); // 3

// Adding elements
fruits.push("grape"); // Add to end
fruits.unshift("kiwi"); // Add to beginning
fruits.splice(2, 0, "mango"); // Insert at index 2

// Removing elements
let last = fruits.pop(); // Remove and return last
let first = fruits.shift(); // Remove and return first
fruits.splice(1, 1); // Remove 1 element at index 1

// Checking bounds
if (fruits[5]) {
    console.log("Element exists");
} else {
    console.log("Index out of bounds");
}
```

```swift !! swift
// Swift array access
var fruits = ["apple", "banana", "orange"]
print(fruits[0]) // "apple"
print(fruits.count) // 3

// Adding elements
fruits.append("grape") // Add to end
fruits.insert("kiwi", at: 0) // Insert at beginning
fruits.insert("mango", at: 2) // Insert at index 2

// Removing elements
let last = fruits.removeLast() // Remove and return last
let first = fruits.removeFirst() // Remove and return first
let removed = fruits.remove(at: 1) // Remove and return element at index 1

// Safe array access
if fruits.indices.contains(5) {
    print("Element exists: \(fruits[5])")
} else {
    print("Index out of bounds")
}

// Using first and last properties
if let firstFruit = fruits.first {
    print("First fruit: \(firstFruit)")
}
if let lastFruit = fruits.last {
    print("Last fruit: \(lastFruit)")
}
```
</UniversalEditor>

### Array Slicing and Range Operations

<UniversalEditor title="Array Slicing and Range Operations" compare={true}>
```javascript !! js
// JavaScript array slicing
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Slicing (start, end)
let slice1 = numbers.slice(2, 5); // [3, 4, 5]
let slice2 = numbers.slice(-3); // [8, 9, 10]
let slice3 = numbers.slice(0, -2); // [1, 2, 3, 4, 5, 6, 7, 8]

// Creating ranges
let range = Array.from({length: 5}, (_, i) => i + 1); // [1, 2, 3, 4, 5]
```

```swift !! swift
// Swift array slicing
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// Slicing with ranges
let slice1 = numbers[2..<5] // [3, 4, 5]
let slice2 = numbers[7...] // [8, 9, 10]
let slice3 = numbers[..<8] // [1, 2, 3, 4, 5, 6, 7, 8]

// Creating ranges
let range = Array(1...5) // [1, 2, 3, 4, 5]
let range2 = Array(1..<6) // [1, 2, 3, 4, 5]

// Using stride for custom ranges
let stepRange = Array(stride(from: 0, to: 10, by: 2)) // [0, 2, 4, 6, 8]
```
</UniversalEditor>

## Dictionaries

Dictionaries in Swift are key-value collections, similar to JavaScript objects but with strong typing for both keys and values.

### Dictionary Declaration and Initialization

<UniversalEditor title="Dictionary Declaration Comparison" compare={true}>
```javascript !! js
// JavaScript object/dictionary
let person = {
    name: "John",
    age: 30,
    city: "New York"
};

// Creating empty object
let emptyObject = {};

// Object with computed properties
let key = "dynamicKey";
let dynamicObject = {
    [key]: "dynamic value",
    staticKey: "static value"
};

// Nested objects
let user = {
    profile: {
        name: "Alice",
        email: "alice@example.com"
    },
    settings: {
        theme: "dark",
        notifications: true
    }
};
```

```swift !! swift
// Swift dictionary
var person: [String: Any] = [
    "name": "John",
    "age": 30,
    "city": "New York"
]

// Type-safe dictionary
var scores: [String: Int] = [
    "Alice": 85,
    "Bob": 92,
    "Charlie": 78
]

// Creating empty dictionary
var emptyDict: [String: Int] = [:]
var emptyDict2 = [String: Int]()

// Dictionary with computed properties
let key = "dynamicKey"
var dynamicDict: [String: String] = [
    key: "dynamic value",
    "staticKey": "static value"
]

// Nested dictionaries
var user: [String: [String: Any]] = [
    "profile": [
        "name": "Alice",
        "email": "alice@example.com"
    ],
    "settings": [
        "theme": "dark",
        "notifications": true
    ]
]
```
</UniversalEditor>

### Dictionary Access and Modification

<UniversalEditor title="Dictionary Access and Modification" compare={true}>
```javascript !! js
// JavaScript object access
let person = { name: "John", age: 30 };

// Accessing properties
console.log(person.name); // "John"
console.log(person["age"]); // 30
console.log(person.address); // undefined

// Safe access with optional chaining
console.log(person.address?.street); // undefined

// Adding/modifying properties
person.city = "New York";
person["occupation"] = "Developer";

// Removing properties
delete person.age;

// Checking if property exists
if ("name" in person) {
    console.log("Name exists");
}

// Getting keys and values
let keys = Object.keys(person);
let values = Object.values(person);
let entries = Object.entries(person);
```

```swift !! swift
// Swift dictionary access
var person: [String: Any] = ["name": "John", "age": 30]

// Accessing values
print(person["name"] as? String ?? "Unknown") // "John"
print(person["age"] as? Int ?? 0) // 30

// Safe access with optional binding
if let name = person["name"] as? String {
    print("Name: \(name)")
}

// Adding/modifying values
person["city"] = "New York"
person["occupation"] = "Developer"

// Removing values
person.removeValue(forKey: "age")
person["age"] = nil // Alternative way

// Checking if key exists
if person["name"] != nil {
    print("Name exists")
}

// Getting keys and values
let keys = Array(person.keys)
let values = Array(person.values)

// Iterating over dictionary
for (key, value) in person {
    print("\(key): \(value)")
}
```
</UniversalEditor>

## Sets

Sets in Swift are unordered collections of unique elements, similar to JavaScript's Set but with strong typing.

### Set Declaration and Operations

<UniversalEditor title="Set Declaration and Operations" compare={true}>
```javascript !! js
// JavaScript Set
let numbers = new Set([1, 2, 3, 4, 5]);
let fruits = new Set(["apple", "banana", "orange"]);

// Creating empty Set
let emptySet = new Set();

// Adding elements
numbers.add(6);
fruits.add("grape");

// Removing elements
numbers.delete(1);
fruits.delete("apple");

// Checking membership
console.log(numbers.has(3)); // true
console.log(fruits.has("mango")); // false

// Set size
console.log(numbers.size); // 5

// Converting to array
let numbersArray = Array.from(numbers);
```

```swift !! swift
// Swift Set
var numbers: Set<Int> = [1, 2, 3, 4, 5]
var fruits: Set<String> = ["apple", "banana", "orange"]

// Creating empty Set
var emptySet: Set<Int> = []
var emptySet2 = Set<Int>()

// Adding elements
numbers.insert(6)
fruits.insert("grape")

// Removing elements
numbers.remove(1)
fruits.remove("apple")

// Checking membership
print(numbers.contains(3)) // true
print(fruits.contains("mango")) // false

// Set count
print(numbers.count) // 5

// Converting to array
let numbersArray = Array(numbers)
```
</UniversalEditor>

### Set Operations

<UniversalEditor title="Set Operations" compare={true}>
```javascript !! js
// JavaScript Set operations
let set1 = new Set([1, 2, 3, 4]);
let set2 = new Set([3, 4, 5, 6]);

// Union
let union = new Set([...set1, ...set2]);

// Intersection
let intersection = new Set(
    [...set1].filter(x => set2.has(x))
);

// Difference
let difference = new Set(
    [...set1].filter(x => !set2.has(x))
);

// Subset check
let isSubset = [...set1].every(x => set2.has(x));

// Superset check
let isSuperset = [...set2].every(x => set1.has(x));
```

```swift !! swift
// Swift Set operations
var set1: Set<Int> = [1, 2, 3, 4]
var set2: Set<Int> = [3, 4, 5, 6]

// Union
let union = set1.union(set2)

// Intersection
let intersection = set1.intersection(set2)

// Difference
let difference = set1.subtracting(set2)

// Symmetric difference
let symmetricDiff = set1.symmetricDifference(set2)

// Subset and superset checks
let isSubset = set1.isSubset(of: set2)
let isSuperset = set1.isSuperset(of: set2)
let isDisjoint = set1.isDisjoint(with: set2)
```
</UniversalEditor>

## Collection Operations

Swift collections provide powerful functional programming methods similar to JavaScript array methods.

### Functional Programming Methods

<UniversalEditor title="Functional Programming with Collections" compare={true}>
```javascript !! js
// JavaScript functional programming
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Map
let doubled = numbers.map(x => x * 2);

// Filter
let evens = numbers.filter(x => x % 2 === 0);

// Reduce
let sum = numbers.reduce((acc, x) => acc + x, 0);

// Find
let firstEven = numbers.find(x => x % 2 === 0);

// Some/Every
let hasEven = numbers.some(x => x % 2 === 0);
let allPositive = numbers.every(x => x > 0);

// FlatMap
let nested = [[1, 2], [3, 4], [5, 6]];
let flattened = nested.flatMap(x => x);

// Chaining
let result = numbers
    .filter(x => x % 2 === 0)
    .map(x => x * 2)
    .reduce((acc, x) => acc + x, 0);
```

```swift !! swift
// Swift functional programming
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// Map
let doubled = numbers.map { $0 * 2 }

// Filter
let evens = numbers.filter { $0 % 2 == 0 }

// Reduce
let sum = numbers.reduce(0) { $0 + $1 }

// First (equivalent to find)
let firstEven = numbers.first { $0 % 2 == 0 }

// Contains (equivalent to some)
let hasEven = numbers.contains { $0 % 2 == 0 }
let allPositive = numbers.allSatisfy { $0 > 0 }

// FlatMap (now compactMap for optionals, flatMap for sequences)
let nested = [[1, 2], [3, 4], [5, 6]]
let flattened = nested.flatMap { $0 }

// Chaining
let result = numbers
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }
    .reduce(0) { $0 + $1 }

// Additional Swift methods
let sorted = numbers.sorted()
let reversed = numbers.reversed()
let shuffled = numbers.shuffled()
```
</UniversalEditor>

### Collection Performance

<UniversalEditor title="Collection Performance Comparison" compare={true}>
```javascript !! js
// JavaScript collection performance considerations
let array = [1, 2, 3, 4, 5];

// Array operations performance
// Push/pop: O(1)
array.push(6);
array.pop();

// Unshift/shift: O(n) - requires shifting all elements
array.unshift(0);
array.shift();

// Index access: O(1)
let element = array[2];

// Search: O(n)
let index = array.indexOf(3);

// Object property access: O(1) average
let obj = { a: 1, b: 2, c: 3 };
let value = obj.a;

// Set operations: O(1) average
let set = new Set([1, 2, 3]);
set.has(2); // O(1) average
```

```swift !! swift
// Swift collection performance considerations
var array = [1, 2, 3, 4, 5]

// Array operations performance
// Append/removeLast: O(1) amortized
array.append(6)
array.removeLast()

// Insert/remove at beginning: O(n) - requires shifting
array.insert(0, at: 0)
array.removeFirst()

// Index access: O(1)
let element = array[2]

// Search: O(n)
if let index = array.firstIndex(of: 3) {
    print("Found at index: \(index)")
}

// Dictionary access: O(1) average
var dict: [String: Int] = ["a": 1, "b": 2, "c": 3]
let value = dict["a"]

// Set operations: O(1) average
var set: Set<Int> = [1, 2, 3]
set.contains(2) // O(1) average

// Swift-specific optimizations
// ContiguousArray for better performance
var fastArray = ContiguousArray<Int>([1, 2, 3, 4, 5])

// Lazy evaluation for large collections
let lazyResult = numbers.lazy
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }

// Only compute when accessed
let firstLazyResult = lazyNumbers.first { $0 > 1000 }
```
</UniversalEditor>

## Functional Programming with Collections

Swift's collection types support powerful functional programming patterns.

### Advanced Functional Operations

<UniversalEditor title="Advanced Functional Operations" compare={true}>
```javascript !! js
// JavaScript advanced functional programming
let students = [
    { name: "Alice", grade: 85, age: 20 },
    { name: "Bob", grade: 92, age: 19 },
    { name: "Charlie", grade: 78, age: 21 },
    { name: "Diana", grade: 95, age: 20 }
];

// Complex filtering and mapping
let topStudents = students
    .filter(student => student.grade >= 90)
    .map(student => ({
        name: student.name,
        grade: student.grade,
        status: "Excellent"
    }));

// Grouping
let groupedByAge = students.reduce((groups, student) => {
    const age = student.age;
    if (!groups[age]) groups[age] = [];
    groups[age].push(student);
    return groups;
}, {});

// Sorting with multiple criteria
let sortedStudents = students.sort((a, b) => {
    if (a.grade !== b.grade) {
        return b.grade - a.grade; // Descending by grade
    }
    return a.name.localeCompare(b.name); // Then by name
});
```

```swift !! swift
// Swift advanced functional programming
struct Student {
    let name: String
    let grade: Int
    let age: Int
}

let students = [
    Student(name: "Alice", grade: 85, age: 20),
    Student(name: "Bob", grade: 92, age: 19),
    Student(name: "Charlie", grade: 78, age: 21),
    Student(name: "Diana", grade: 95, age: 20)
]

// Complex filtering and mapping
let topStudents = students
    .filter { $0.grade >= 90 }
    .map { student in
        (name: student.name, grade: student.grade, status: "Excellent")
    }

// Grouping
let groupedByAge = Dictionary(grouping: students) { $0.age }

// Sorting with multiple criteria
let sortedStudents = students.sorted { first, second in
    if first.grade != second.grade {
        return first.grade > second.grade // Descending by grade
    }
    return first.name < second.name // Then by name
}

// Additional Swift functional features
// CompactMap for optional handling
let optionalNumbers = ["1", "2", "three", "4", "5"]
let validNumbers = optionalNumbers.compactMap { Int($0) }

// Prefix and suffix
let firstThree = Array(students.prefix(3))
let lastTwo = Array(students.suffix(2))

// Partition
var mutableStudents = students
let partitionIndex = mutableStudents.partition { $0.grade >= 85 }
let highAchievers = Array(mutableStudents[..<partitionIndex])
let others = Array(mutableStudents[partitionIndex...])
```
</UniversalEditor>

## Performance Considerations

Understanding performance characteristics helps write efficient Swift code.

### Memory and Performance Optimization

<UniversalEditor title="Performance Optimization" compare={true}>
```javascript !! js
// JavaScript performance considerations
// Array performance
let largeArray = new Array(1000000).fill(0);

// Efficient array operations
// Use push/pop instead of unshift/shift for large arrays
let efficientArray = [];
for (let i = 0; i < 1000; i++) {
    efficientArray.push(i); // O(1)
}

// Object property access optimization
let optimizedObject = {};
// Pre-define properties for better performance
optimizedObject.prop1 = 1;
optimizedObject.prop2 = 2;

// Set for unique values
let uniqueValues = new Set();
for (let i = 0; i < 1000; i++) {
    uniqueValues.add(i % 100); // Only 100 unique values
}
```

```swift !! swift
// Swift performance considerations
// Array performance
var largeArray = Array(repeating: 0, count: 1_000_000)

// Use ContiguousArray for better performance
var fastArray = ContiguousArray<Int>()

// Efficient array operations
for i in 0..<1000 {
    fastArray.append(i) // O(1) amortized
}

// Reserve capacity for better performance
var optimizedArray = [Int]()
optimizedArray.reserveCapacity(1000) // Pre-allocate memory

// Dictionary optimization
var optimizedDict = [String: Int]()
optimizedDict.reserveCapacity(100) // Pre-allocate memory

// Set for unique values
var uniqueValues = Set<Int>()
for i in 0..<1000 {
    uniqueValues.insert(i % 100) // Only 100 unique values
}

// Lazy evaluation for large collections
let lazyNumbers = (1...1_000_000).lazy
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }

// Only compute when accessed
let firstLazyResult = lazyNumbers.first { $0 > 1000 }
```
</UniversalEditor>

## Exercises

### Exercise 1: Array Operations
Create a function that takes an array of integers and returns a new array containing only the even numbers, doubled.

<UniversalEditor title="Exercise 1 Solution" compare={true}>
```javascript !! js
// JavaScript solution
function getDoubledEvens(numbers) {
    return numbers
        .filter(num => num % 2 === 0)
        .map(num => num * 2);
}

// Test
let testNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(getDoubledEvens(testNumbers)); // [4, 8, 12, 16, 20]
```

```swift !! swift
// Swift solution
func getDoubledEvens(_ numbers: [Int]) -> [Int] {
    return numbers
        .filter { $0 % 2 == 0 }
        .map { $0 * 2 }
}

// Test
let testNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(getDoubledEvens(testNumbers)) // [4, 8, 12, 16, 20]
```
</UniversalEditor>

### Exercise 2: Dictionary Operations
Create a function that counts the frequency of each character in a string.

<UniversalEditor title="Exercise 2 Solution" compare={true}>
```javascript !! js
// JavaScript solution
function countCharacters(str) {
    const charCount = {};
    for (let char of str) {
        charCount[char] = (charCount[char] || 0) + 1;
    }
    return charCount;
}

// Test
console.log(countCharacters("hello")); // { h: 1, e: 1, l: 2, o: 1 }
```

```swift !! swift
// Swift solution
func countCharacters(_ str: String) -> [Character: Int] {
    var charCount: [Character: Int] = [:]
    for char in str {
        charCount[char, default: 0] += 1
    }
    return charCount
}

// Test
print(countCharacters("hello")) // ["h": 1, "e": 1, "l": 2, "o": 1]
```
</UniversalEditor>

### Exercise 3: Set Operations
Create a function that finds the intersection of two arrays (common elements).

<UniversalEditor title="Exercise 3 Solution" compare={true}>
```javascript !! js
// JavaScript solution
function findIntersection(arr1, arr2) {
    const set1 = new Set(arr1);
    const set2 = new Set(arr2);
    return [...set1].filter(x => set2.has(x));
}

// Test
let array1 = [1, 2, 3, 4, 5];
let array2 = [3, 4, 5, 6, 7];
console.log(findIntersection(array1, array2)); // [3, 4, 5]
```

```swift !! swift
// Swift solution
func findIntersection(_ arr1: [Int], _ arr2: [Int]) -> [Int] {
    let set1 = Set(arr1)
    let set2 = Set(arr2)
    return Array(set1.intersection(set2))
}

// Test
let array1 = [1, 2, 3, 4, 5]
let array2 = [3, 4, 5, 6, 7]
print(findIntersection(array1, array2)) // [3, 4, 5]
```
</UniversalEditor>

## Key Takeaways

### Swift Collection Advantages
1. **Type Safety**: All collections are strongly typed, preventing runtime errors
2. **Performance**: Optimized implementations with predictable performance characteristics
3. **Functional Programming**: Rich set of functional methods for data transformation
4. **Memory Safety**: Automatic memory management with ARC
5. **Value Semantics**: Arrays and dictionaries are value types, providing predictable behavior

### Key Differences from JavaScript
1. **Type System**: Swift collections require explicit or inferred types
2. **Mutability**: Swift distinguishes between mutable and immutable collections
3. **Performance**: Swift collections have more predictable performance characteristics
4. **Memory Management**: Automatic reference counting vs garbage collection
5. **Value Types**: Swift arrays and dictionaries are value types, not reference types

### Best Practices
1. **Use appropriate collection types** for your data needs
2. **Leverage functional programming methods** for data transformation
3. **Consider performance implications** when choosing operations
4. **Use type inference** when possible for cleaner code
5. **Pre-allocate capacity** for large collections when possible
6. **Use lazy evaluation** for large data transformations

### Next Steps
In the next module, we'll explore control flow in Swift, including conditional statements, loops, and pattern matching with switch statements. This will build upon our understanding of collections and show how to process data effectively in Swift. 